Re: [linux-security] Things NOT to put in root's crontab

Zygo Blaxell (zblaxell@myrus.com)
Thu, 23 May 1996 18:27:20 -0400

Quoted from Philip Guenther:
> The race condition in find should be eliminatible by using fchdir()
> and passing the '-exec'ed command a simple filename.  You have to keep
> open one descriptor for each level descended which should max out at
> MAXPATHLEN/2.  That should be within the bounds of modern UNIX systems.

> In pseudocode:
>
> cur = open argv[1];
> fchdir(cur);
> do_dir(cur);
>
> do_dir(int cur) {
>     foreach file in "." {
### vulnerability here ###
>         int fd = open file;
### vulnerability here ###
>         do_stuff_from_command_line;
>         if ISDIR(fstat fd) {
>             fchdir(fd);
>             do_dir(fd);
>             fchdir(cur);
>         }
>     }
> }

Correct, except that it is necessary to check that 'open file' didn't
follow a symlink.  Actually, without this check, this pseudocode is much
worse than current find implementations, because it follows *all*
symlinks to directories, no racing necessary.

Here's something that may be cleaner.  In this pseudocode language, all
system calls throw an exception on failure that exits the current
function.

find {
        int first_dir_fd=opendir(.);
        foreach directory on commandline {
                // not necessary to check stuff we're given
                chdir(directory);
                recursively_process_current_directory;
                fchdir(first_dir_fd);
        }
}
recursively_process_current_directory {
        try {
                foreach file in "." {
                        A=lstat(file);
                        do_stuff_from_command_line;
                        if (ISDIR(A)) {
                                int parentwd_fd=opendir(.);
                                B=lstat(.);             //optional
                                chdir(file);
                                C=lstat(.);
                                D=lstat(..);            //optional
                                if (
                                        A!=C            //mandatory
                                        || B!=D         //optional
                                ) {
                                        print_warning;
                                        return error;
                                }
                                recursively_process_current_directory();
                                fchdir(parentwd_fd);
                        }
                }
        }
}

The parts marked 'optional' above I don't think you really need.

All parameters to 'exec' are relative to the current directory.  To
prevent most Unix commands from getting confused, optionally prepend
'./' to each filename.

--
Zygo Blaxell.  Former Unix/soft/hardware guru, U of Waterloo Computer Science
Club.  Current sysadmin for Myrus Design, Inc.  10th place, ACM Intl Collegiate
Programming Contest Finals, 1994.  Administer Linux nets for food, clothing,
and anime.  "I gave up $1000 to avoid working on windoze... *sigh*" - Amy Fong